﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PoolMemberService.cs" company="">
//   
// </copyright>
// <summary>
//   The pool member service.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace F5.BigIp.LocalTrafficManager.Proxy.V11
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using F5.BigIp.LocalTrafficManager.Interfaces;
    using F5.BigIp.LocalTrafficManager.Proxy.V11.LocalLB.PoolMember;

    /// <summary>The pool member service.</summary>
    public class PoolMemberService : IPoolMemberService
    {
        #region Public Methods and Operators

        /// <summary>The get pool members.</summary>
        /// <param name="pool">The pool.</param>
        /// <returns>The <see cref="IEnumerable"/>.</returns>
        public IEnumerable<IPoolMember> GetPoolMembers(IPool pool)
        {
            LocalLB.Pool.LocalLBPoolPortType poolService = ServiceFactory.CreatePoolService(pool.LoadBalancer);

            var poolMembersJaggedArray =
                poolService.get_member_v2(new LocalLB.Pool.get_member_v2Request(new[] { pool.Name })).@return;

            var poolMembersStatistics =
                poolService.get_member_statistics(
                    new LocalLB.Pool.get_member_statisticsRequest(new[] { pool.Name }, poolMembersJaggedArray)).@return[0].statistics;

            var poolMembersStatus =
                poolService.get_member_object_status(
                    new LocalLB.Pool.get_member_object_statusRequest(new[] { pool.Name }, poolMembersJaggedArray)).@return[0];

            var poolMembersArray = poolMembersJaggedArray[0];

            return
                poolMembersArray.Select(
                    (t, i) =>
                    new PoolMember(pool.LoadBalancer, pool, t.address, (int)t.port)
                        {
                            Status =
                                poolMembersStatus[i]
                                .ToPoolMemberStatus(),
                            Statistics =
                                poolMembersStatistics[i]
                                .ToPoolMemberStatistics(),
                            LastUpdate = DateTime.Now
                        })
                                .Cast<IPoolMember>()
                                .ToList();
        }

        /// <summary>The get statistics.</summary>
        /// <param name="member">The member.</param>
        /// <returns>The <see cref="PoolMemberStatistics"/>.</returns>
        public PoolMemberStatistics GetStatistics(PoolMember member)
        {
            var poolMemberStatistics = new PoolMemberStatistics();

            LocalLBPoolMemberPortType poolMemberService = ServiceFactory.CreatePoolMemberService(member.LoadBalancer);

            var poolMember = new CommonIPPortDefinition { address = member.Address, port = member.Port };

            var memberJaggedArray = new[] { new[] { poolMember } };

            get_statisticsResponse result =
                poolMemberService.get_statistics(new get_statisticsRequest(new[] { member.Pool.Name }, memberJaggedArray));

            CommonStatistic[] statistics = result.@return[0].statistics[0].statistics;

            CommonStatistic currentConnections =
                statistics.FirstOrDefault(k => k.type == CommonStatisticType.STATISTIC_SERVER_SIDE_CURRENT_CONNECTIONS);

            if (currentConnections != null)
            {
                poolMemberStatistics.CurrentConnections = (int)currentConnections.value.low;
            }

            return poolMemberStatistics;
        }

        /// <summary>The set monitor state.</summary>
        /// <param name="member">The member.</param>
        /// <param name="enabled">The enabled.</param>
        public void SetMonitorState(IPoolMember member, bool enabled)
        {
            LocalLBPoolMemberPortType poolMemberService = ServiceFactory.CreatePoolMemberService(member.LoadBalancer);

            var monitorState = new LocalLBPoolMemberMemberMonitorState
                                   {
                                       monitor_state =
                                           enabled
                                               ? CommonEnabledState.STATE_ENABLED
                                               : CommonEnabledState.STATE_DISABLED,
                                       member =
                                           new CommonIPPortDefinition
                                               {
                                                   address =
                                                       member
                                                       .Address,
                                                   port =
                                                       member
                                                       .Port
                                               }
                                   };

            var monitorStateJaggedArray = new[] { new[] { monitorState } };

            poolMemberService.set_monitor_state(
                new set_monitor_stateRequest(new[] { member.Pool.Name }, monitorStateJaggedArray));
        }

        /// <summary>The set session state.</summary>
        /// <param name="member">The member.</param>
        /// <param name="enabled">The enabled.</param>
        public void SetSessionState(IPoolMember member, bool enabled)
        {
            LocalLBPoolMemberPortType poolMemberService = ServiceFactory.CreatePoolMemberService(member.LoadBalancer);

            var sessionState = new LocalLBPoolMemberMemberSessionState
                                   {
                                       session_state =
                                           enabled
                                               ? CommonEnabledState.STATE_ENABLED
                                               : CommonEnabledState.STATE_DISABLED,
                                       member =
                                           new CommonIPPortDefinition
                                               {
                                                   address =
                                                       member
                                                       .Address,
                                                   port =
                                                       member
                                                       .Port
                                               }
                                   };

            var sessionStateJaggedArray = new[] { new[] { sessionState } };

            poolMemberService.set_session_enabled_state(
                new set_session_enabled_stateRequest(new[] { member.Pool.Name }, sessionStateJaggedArray));
        }

        /// <summary>Enable pool member.</summary>
        /// <param name="poolMember">The pool member.</param>
        public void EnablePoolMember(IPoolMember poolMember)
        {
            this.SetSessionState(poolMember, true);

            this.SetMonitorState(poolMember, true);
        }

        /// <summary>Disable pool member.</summary>
        /// <param name="poolMember">The pool member.</param>
        public void DisablePoolMember(IPoolMember poolMember)
        {
            this.SetSessionState(poolMember, false);

            this.SetMonitorState(poolMember, true);
        }

        /// <summary>Take pool member offline.</summary>
        /// <param name="poolMember">The pool member.</param>
        public void ForcePoolMemberOffline(IPoolMember poolMember)
        {
            this.SetSessionState(poolMember, false);

            this.SetMonitorState(poolMember, false);
        }

        #endregion
    }
}